package com.pinkpig.excel.xml;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.pinkpig.excel.ext.ThrowErrorHandler;
import com.pinkpig.excel.metadata.config.DatabaseConfiguration;
import com.pinkpig.excel.xml.config.TableExportConfiguration;
import com.pinkpig.excel.xml.config.TableExportContext;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

/**
 * @author vincenfeng
 */
public class TableExportConfigurationParser {

    private static final String CONFIGURATION = "configuration";
    private static final String JDBC_CONNECTION = "jdbcConnection";
    private static final String CONTEXT = "context";
    private static final String TABLE_CATEGORY = "tableCategory";
    private static final String TABLE_EXCLUDE = "tableExclude";
    private static final String TABLE = "table";
    private static final String NAME = "name";
    private static final String DRIVER_CLASS = "driverClass";
    private static final String CONNECTION_URL = "connectionURL";
    private static final String USER_ID = "userId";
    private static final String PASSWORD = "password";
    private static final String OTHER_CATEGORY = "其他";

    public TableExportConfiguration parse(URL url) throws ParserConfigurationException, IOException, SAXException {
        TableExportConfiguration configuration = new TableExportConfiguration();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(true);
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        documentBuilder.setErrorHandler(new ThrowErrorHandler());
        Document document = documentBuilder.parse(url.toString());
        Element rootElement = document.getDocumentElement();

        if(rootElement.getNodeType()== Node.ELEMENT_NODE){
            parseConfiguration(configuration, rootElement);
        }
        return configuration;
    }

    private void parseConfiguration(TableExportConfiguration configuration, Element rootElement){
        NodeList contextNode = rootElement.getChildNodes();
        IntStream.range(0, contextNode.getLength()).forEach(i -> {
            if (contextNode.item(i).getNodeType() != Node.ELEMENT_NODE) {
                return;
            }
            if(CONTEXT.equals(contextNode.item(i).getNodeName())){
                TableExportContext context = new TableExportContext();
                parseContext(context, contextNode.item(i));
                configuration.setTableExportContext(context);
            }else if(JDBC_CONNECTION.equals(contextNode.item(i).getNodeName())){
                String driverClass = getAttributeValue(contextNode.item(i), DRIVER_CLASS);
                String connectionURL = getAttributeValue(contextNode.item(i), CONNECTION_URL);
                String userId = getAttributeValue(contextNode.item(i), USER_ID);
                String password = getAttributeValue(contextNode.item(i), PASSWORD);
                DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration(userId, password, connectionURL, driverClass);
                configuration.setDatabaseConfiguration(databaseConfiguration);
            }
        });
    }

    private void parseContext(TableExportContext context, Node contextNode){
        NodeList childNodes = contextNode.getChildNodes();
        IntStream.range(0, childNodes.getLength()).forEach(i -> {
            if (childNodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
                return;
            }
            String nodeName = childNodes.item(i).getNodeName();
            if(TABLE_CATEGORY.equals(nodeName)){
                String tableCategory = getAttributeValue(childNodes.item(i), NAME);
                NodeList tableNodes = childNodes.item(i).getChildNodes();
                IntStream.range(0, tableNodes.getLength()).forEach(n -> {
                    if (tableNodes.item(n).getNodeType() != Node.ELEMENT_NODE) {
                        return;
                    }
                    if(TABLE.equals(tableNodes.item(n).getNodeName())){
                        String tableName = getAttributeValue(tableNodes.item(n), NAME);
                        context.getTableCategoryMap().put(tableName, tableCategory);
                        if(context.getCategoryTablesMap().containsKey(tableCategory)){
                            context.getCategoryTablesMap().get(tableCategory).add(tableName);
                        }else{
                            List<String> tables = new ArrayList<>();
                            tables.add(tableName);
                            context.getCategoryTablesMap().put(tableCategory, tables);
                        }
                    }
                });
            }else if(TABLE_EXCLUDE.equals(nodeName)){
                NodeList tableNodes = childNodes.item(i).getChildNodes();
                IntStream.range(0, tableNodes.getLength()).forEach(n -> {
                    if(TABLE.equals(tableNodes.item(n).getNodeName())){
                        String tableName = getAttributeValue(tableNodes.item(n), NAME);
                        context.getExcludeTables().add(tableName);
                    }
                });
            }
        });
    }

    private String getAttributeValue(Node node, String attrName){
        NamedNodeMap namedNodeMap = node.getAttributes();
        Node nameAttr = namedNodeMap.getNamedItem(attrName);
        if(null!=nameAttr){
            return nameAttr.getNodeValue();
        }
        return null;
    }

}
